Skip to content

Add HtmlRenderer.Test project, port applicable tests from PeachPDF - #262

Open
jhaygood86 wants to merge 5 commits into
ArthurHub:masterfrom
jhaygood86:port-peachpdf-tests
Open

Add HtmlRenderer.Test project, port applicable tests from PeachPDF#262
jhaygood86 wants to merge 5 commits into
ArthurHub:masterfrom
jhaygood86:port-peachpdf-tests

Conversation

@jhaygood86

@jhaygood86 jhaygood86 commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Ports applicable tests from PeachPDF's test suite (PeachPDF forked from HTML-Renderer and has since built out a much larger feature set) into three MSTest projects, routed by what each test actually exercises:

  • HtmlRenderer.Test (new) — pure unit tests against the core library: CSS engine/parsing, DOM/layout utilities. Backed by a lightweight mock RAdapter/RGraphics test harness with no UI-framework dependency.
  • HtmlRenderer.IntegrationTest — end-to-end layout/paint behavior tests, using a similar harness backed by the real WinForms adapter.
  • HtmlRenderer.PdfSharp.Test — PDF-generation and PdfSharp-adapter tests.

This PR was opened when HTML-Renderer still had its old, much more limited hand-rolled CSS parser, so only ~41 of PeachPDF.Tests' ~483 files were portable at the time. Since then, HTML-Renderer absorbed a full CSS engine port from PeachPDF/ExCSS (Source/HtmlRenderer/Core/CssEngine/, a near-1:1 structural clone of PeachPDF's own CSS engine), which changed the picture substantially — most of PeachPDF.Tests/CSS/ tests the CSS parsing/CSSOM layer in isolation, and that layer is now close to feature-complete. This PR was updated to:

  1. Fix the ~20 files ported before the CSS engine landed, which broke against the new APIs (adapter signature drift, removed legacy parsing methods, a proprietary corner-radius mechanism replaced by real border-radius).
  2. Re-verify all 111 previously [Ignore("not yet spec compliant")] tests against the current codebase — 28 now genuinely pass (mostly CssLength unit-conversion coverage, several layout edge cases, and a couple of table visibility:collapse/vertical-align cases) and are un-ignored; the rest still fail for their originally-documented reasons, which the CSS engine port never touched (it replaced parsing, not the box/layout/paint engine).
  3. Re-triage and port the remaining ~86 files in PeachPDF.Tests/CSS/ against the new engine — the vast majority are now portable, since they test parsing/CSSOM in isolation rather than rendered behavior.

What's still excluded, and why: PeachPDF.Tests/Html/, Integration/, PdfSharpCore/, Svg/, and misc folders (~415 files) have not been re-triaged against the new engine in this pass — those test rendered behavior (layout/paint), and CSS-parsing support doesn't imply layout support. Confirmed directly: flexbox, grid, transform, box-shadow, and animations all parse correctly now but have zero consumption anywhere in the layout/paint engine (CssLayoutEngine.cs has no "flex"/"grid" references, no paint handler draws a shadow or applies a transform). border-radius is the one exception, genuinely painted end-to-end. Also still absent regardless of layer: WOFF/WOFF2 binary decoding, GCPM paged-media content functions (leader(), target-counter(), running(), etc.), SVG rendering, :has() with leading combinators, and font-variant granular sub-properties.

Where a ported test exercises a feature that does exist but isn't yet spec-compliant, it's still ported with its full original assertions intact — documenting the real target behavior — but marked [Ignore("not yet spec compliant")] with a doc comment citing the exact source evidence for the gap. This pass surfaced several new gaps this way: gap/row-gap/column-gap reject the normal keyword, font-weight only accepts the legacy CSS2.1 100-900 multiples (not the full [1,1000] range), GridTemplate/GridTrackSize have no value-equality, @supports/@container parse but are never consulted by the real per-box cascade, and cascade-layer precedence isn't implemented (rules in @layer are treated as ordinary unlayered rules).

Adds InternalsVisibleTo grants from HtmlRenderer/HtmlRenderer.WinForms/HtmlRenderer.PdfSharp to their respective test projects, matching the same grants PeachPDF's own .csproj already declares for PeachPDF.Tests. No behavioral changes to HTML-Renderer itself.

More tests will be ported incrementally as HTML-Renderer's layout/paint engine catches up to what the CSS engine can already parse, and as the remaining PeachPDF.Tests folders get their own re-triage pass.

Test plan

  • dotnet build Source/HtmlRenderer.sln (Release) — clean, 0 errors
  • dotnet test per project:
    • HtmlRenderer.Test: 2367 passed, 0 failed, 123 skipped (ignored, spec-compliance gaps)
    • HtmlRenderer.IntegrationTest (new tests): 92 passed, 0 failed, 74 skipped
    • HtmlRenderer.PdfSharp.Test: 15 passed, 0 failed
  • All 9 CI matrix jobs (Windows/Ubuntu/macOS × .NET 8/9/10) pass.

PeachPDF forked from HTML-Renderer and has since built out a much
larger CSS engine, SVG support, and PDF pipeline, with a large xUnit
test suite covering it. This adds a new HtmlRenderer.Test project
(MSTest, matching this repo's existing test style) and ports the
subset of PeachPDF.Tests that HTML-Renderer's current feature set can
actually exercise, routing tests to the appropriate project:

- HtmlRenderer.Test: CSS parsing/property and Core Dom/Utils unit
  tests, using a new lightweight mock RAdapter/RGraphics test harness
  (no dependency on any UI framework).
- HtmlRenderer.IntegrationTest: end-to-end layout/paint behavior
  tests, using a similar harness backed by the real WinForms adapter.
- HtmlRenderer.PdfSharp.Test: PDF-generation and PdfSharp-adapter
  tests.

Of the ~483 candidate test files, the large majority test PeachPDF
features HTML-Renderer doesn't have at all (its own CSS engine, SVG,
flexbox/grid, shadows/gradients, WOFF fonts, bidi text shaping, etc.)
and were left out. Where a ported test exercises a feature that does
exist in HTML-Renderer but whose current implementation isn't spec
compliant, the test is still ported (full assertions intact, so it
documents the real target behavior) but marked
[Ignore("not yet spec compliant")] rather than dropped or forced to
pass.

InternalsVisibleTo grants were added to HtmlRenderer/HtmlRenderer.WinForms/
HtmlRenderer.PdfSharp for their respective test projects, matching the
same grants PeachPDF's own csproj already declares for PeachPDF.Tests.

More tests will be ported incrementally from PeachPDF as HTML-Renderer
backports more of its standard/spec support.
dotnet test's underlying MSBuild VSTest target only accepts a single
project (MSB1008: Only one project can be specified), unlike dotnet
build. The non-Windows test step passed the *.Test.csproj glob
straight to dotnet test, which happened to work when only one project
matched it, but now that HtmlRenderer.Test.csproj also matches, dotnet
expands the glob to two paths and the step fails outright. Iterate and
test each matching project individually instead.
@eXpl0it3r
eXpl0it3r force-pushed the port-peachpdf-tests branch from 0571cb4 to 69f5ef0 Compare August 21, 2026 19:31
@eXpl0it3r

Copy link
Copy Markdown
Collaborator

Rebased onto master and removed Claude co-author attribution

Between opening this PR and now, HTML-Renderer's old hand-rolled CSS
parser/CssData was replaced by a real ExCSS-derived engine, and
RAdapter/RGraphicsPath/PdfGenerator gained new signatures (multi-stop
gradients, @font-face loading, elliptical ArcTo radii, async PDF
generation). Rebasing this branch onto that work left several ported
test files referencing now-removed APIs (CssParser.ParseCssBlock,
CssData.GetCssBlock/ContainsCssBlock, CssParser.ParseBorder, the
proprietary corner-radius/ActualCornerNw mechanism).

- MockAdapter/RecordingGraphics (both HtmlRenderer.Test and
  HtmlRenderer.IntegrationTest): implement the new
  CreateLinearGradientBrush(RPoint, RPoint, stops[]) and
  LoadFontFaceFontInt overloads, and the 5-arg ArcTo signature.
- PdfGeneratorTests: await the now-async PdfGenerator.GeneratePdf.
- The 7 CSS unit tests that parsed raw property strings directly now
  go through CssParser.ParseInlineStyle/IStyleRule for
  declaration-level checks, or the full LayoutHarness pipeline for
  cascade-level checks, matching how the rest of this port already
  verifies behavior.
- BorderRadiusIntegrationTests: rewritten against the new engine's
  real, spec-compliant border-radius properties
  (ActualBorderTopLeftRadiusX/Y etc.), replacing the now-removed
  proprietary corner-radius workaround this test previously had to use.

Since the real engine fixes several of the compliance gaps the
original port had to mark [Ignore("not yet spec compliant")] for,
those tests are un-ignored here (cascade specificity, media-query
not/only/comma-lists, several illegal-value rejections, all of
border-radius). One new regression the port surfaced (a NullReferenceException
in the new CSS-Nesting parser on malformed split <style> content) is
newly marked [Ignore] with the verified root cause, rather than fixed
here or silently dropped.
@jhaygood86
jhaygood86 force-pushed the port-peachpdf-tests branch from 24d0280 to bf2de64 Compare August 22, 2026 16:33
Re-ran all 111 previously [Ignore("not yet spec compliant")] tests
across HtmlRenderer.Test and HtmlRenderer.IntegrationTest against the
current codebase. 28 of them now genuinely pass:

- HtmlRenderer.Test: 17 of 26 (mostly CssLength unit-conversion/
  comparison-operator coverage, plus vertical-align keyword
  rejection).
- HtmlRenderer.IntegrationTest: 11 of 85 (float-adjacent placement/
  margin-collapse, table visibility:collapse edge cases, two CSS
  content-escaping/attribute-entity-decoding cases, vertical-align
  percentage/text-top metrics).

The remaining 83 still fail for their originally-documented reasons
(mostly CssBox/CssLayoutEngine layout-engine bugs unrelated to CSS
parsing, which this port never touched) and are left [Ignore]d with
their original, already-verified reasoning intact.
…engine

HTML-Renderer's CSS parsing has since been replaced by a full engine
port from PeachPDF/ExCSS (Source/HtmlRenderer/Core/CssEngine/, a
near-1:1 structural clone of PeachPDF's CSS engine). Re-triaged all 97
files in PeachPDF.Tests/CSS/ against the new engine and ported the ~86
files not already handled in the prior pass.

- Added Source/Test/HtmlRenderer.Test/CssEngineSupport/: helper
  classes (CssConstructionFunctions, TestExtensions,
  ObjectArrayComparer) mirroring PeachPDF's own test-construction
  helpers, adapted to the internal TheArtOfDev.HtmlRenderer.Core.CssEngine
  namespace (accessible via the existing InternalsVisibleTo grant).
- Added ~73 new test files under Source/Test/HtmlRenderer.Test/Css/
  (and a Css/Selectors/ subfolder) covering the CSS object model
  (stylesheet parsing, tokenization, selectors, colors, URLs),
  at-rules (@font-face, @Property, @container, @layer, @Keyframes,
  @supports, CSS nesting), grammar/value converters (aspect-ratio,
  basic-shape, box-shadow, calc(), gradients, grid), and the full
  property-test suite (flexbox, backgrounds, borders, fonts, columns,
  content, custom properties, etc.).
- Tests exercising features that still don't exist (GCPM paged-media
  content functions, SVG rendering, WOFF binary decoding, font-variant
  granular sub-properties, `:has()` leading combinators) are excluded
  entirely rather than ported. Tests exercising a real gap in an
  otherwise-working feature are ported with full original assertions
  intact but marked [Ignore("not yet spec compliant")], citing the
  exact source evidence - including several new gaps this pass found
  itself (missing `normal` keyword on gap/row-gap/column-gap,
  font-weight's CSS2.1-only 100-900 restriction, GridTemplate/
  GridTrackSize missing value-equality, @supports/@container never
  applied by the real per-box cascade, cascade-layer precedence not
  implemented).
- Also re-verified all 111 previously [Ignore]d tests against the
  current codebase: 28 now genuinely pass and are un-ignored (see the
  prior commit), the rest still fail for their originally-documented
  layout-engine reasons, which the CSS engine port never touched.

HtmlRenderer.Test: 2367 passed, 0 failed, 123 skipped.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants